package gitee.derumin.railway_accelerator.things;

import net.minecraft.entity.vehicle.AbstractMinecartEntity;
import net.minecraft.util.math.Vec3d;

public interface MinecartPlus {

    default void railway_accelerator$setTrain(MinecartTrain train){}
    default MinecartTrain railway_accelerator$getTrain(){
        return null;
    }
    default double railway_accelerator$getMass(){
        return 1.0d;
    }
    default double railway_accelerator$getPush(){
        return 0.0d;
    }
    default double railway_accelerator$getResistance(){
        return 0.0d;
    }
    default ConnectionStatus railway_accelerator$follow(AbstractMinecartEntity goal, double delta, boolean firstMove){
        return ConnectionStatus.DEFAULT;
    }
    default double railway_accelerator$moveOneStep(double tickRemains, boolean firstMove){
        return 1.0d;
    }
    default void railway_accelerator$updateLineVelocity(double lineV){}
    default double railway_accelerator$getLineVelocity(){
        return 0d;
    }
    default void railway_accelerator$updateHorizontalVector(double x, double z){}
    default HorizontalVector railway_accelerator$getHorizontalVector(){
        return HorizontalVector.DEFAULT;
    }
    default void railway_accelerator$flip(){}
    default void railway_accelerator$forceNotOnRail(){}

    enum ConnectionStatus{
        CONNECT(true, 1.0d),
        HORIZONTAL_BROKEN(false, 0.75d),
        VERTICAL_BROKEN(false, 1.0d),
        DEFAULT(false, 0d);

        private final boolean connect;
        private final double velocityMultiplier;
        ConnectionStatus(boolean connect, double velocityMultiplier){
            this.connect = connect;
            this.velocityMultiplier = velocityMultiplier;
        }

        public boolean isConnect(){
            return this.connect;
        }

        public double getVelocityMultiplier(){
            return this.velocityMultiplier;
        }
    }

    enum YFixes{
        FLAT{
            @Override
            public double calcYSpeed(double accurateV, double prevVY){
                return 0d;
            }
        },
        UP{
            @Override
            public double calcYSpeed(double accurateV, double prevVY){
                return accurateV;
            }
        },
        DOWN{
            @Override
            public double calcYSpeed(double accurateV, double prevVY){
                return -accurateV;
            }
        },
        KEEP{
            @Override
            public double calcYSpeed(double accurateV, double prevVY){
                return prevVY;
            }
        };

        public abstract double calcYSpeed(double accurateV, double prevVY);
    }

    record MoveData(Vec3d move, double rotateX, double rotateZ, double lineV, YFixes yFixes, double deltaCost, double compressBoxY){
        public static MoveData noMove(double rotateX, double rotateZ, double deltaCost){
            return new MoveData(Vec3d.ZERO, rotateX, rotateZ, 0d, YFixes.FLAT, deltaCost, 0d);
        }

        public Vec3d getVelocity(double accurateV, double prevVY){
            return new Vec3d(rotateX * accurateV, yFixes.calcYSpeed(accurateV, prevVY),  rotateZ * accurateV);
        }
    }

    record HorizontalVector(Double x, Double z){
        public static HorizontalVector DEFAULT = new HorizontalVector(0d, 1d);
        public double innerProduct(HorizontalVector v1){
            return this.x*v1.x + this.z*v1.z;
        }
    }
}
